/*
 * Flashlib - QB9 common Flash library
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package com.qb9.flashlib.audio
{
	/**
	 * Allows easy manipulation of many Audio instances.
	 * @see Audio
	 */
	public class AudioMixer implements IAudioManager
	{
		protected var items:Object = { };
		protected var gains:Object = { };
		
		protected var master:Number = 1;
		
		public function AudioMixer()
		{
		}
		
		/**
		 * Adds a new IPlayable to the playlist.
		 * 
		 * @param asset An asset instance
		 * @throws Error The IPlayable instance must have an 'id'.
		 * @see IPlayable
		 */
		
		public function add(asset:IPlayable) : AudioMixer
		{
			if (!asset.id)
				throw new Error('com.flashlib.audio.AudioMixer > Received an IPlayable with no "id".');

			if (items[asset.id])
				remove(asset.id);
			
			items[ asset.id ] = asset;
			gains[ asset.id ] = asset.volume;
			
			_updateVolume(asset);

			return this;
		}		

		/* Private helpers */
		 
		protected function _forEach(id:String, fn:Function) : AudioMixer
		{
			if (id)
			{
				// supports comma/space separated ids
				var ids:Array = id.split(/[\s,]+/);
				for each(id in ids)
				{
					if (items[id])
						fn(items[id]);
					else
						trace('com.flashlib.audio.AudioMixer > Id "'+id+'" not found'); 
				}
			}
			else
			{
				for (id in items)
					fn(items[id]);
			}
			return this;
		}
		
		protected function _updateVolume(asset:IPlayable) : void
		{
			if (gains[asset.id])
				asset.volume = gains[asset.id] * master;
		}
		
		/* Batched methods */
		
		/** @inheritDoc */	
		public function play(id:String = null) : IAudioManager
		{
			return _forEach(id, _play);
		}
		
		protected function _play(asset:IPlayable):void
		{
			asset.play();
		}
		
		/** @inheritDoc */	
		public function loop(id:String = null, times:int = int.MAX_VALUE) : IAudioManager
		{
			return _forEach(id, function(asset:IPlayable) : void {
				asset.loop(times);
			});
		}
		
		/** @inheritDoc */	
		public function resume(id:String = null) : IAudioManager
		{
			return _forEach(id, _resume);
		}
		
		protected function _resume(asset:IPlayable) : void
		{
			asset.resume();
		}
		
		/** @inheritDoc */	
		public function stop(id:String = null) : IAudioManager
		{
			return _forEach(id, _stop);
		}
		
		protected function _stop(asset:IPlayable) : void 
		{
			asset.stop();
		}
		
		/** @inheritDoc */	
		public function pause(id:String = null) : IAudioManager
		{
			return _forEach(id, _pause);
		}
		
		protected function _pause(asset:IPlayable) : void 
		{
			asset.pause();
		}
		
		/** @inheritDoc */	
		public function mute(id:String = null) : IAudioManager
		{
			return _forEach(id, _mute);
		}
		
		protected function _mute(asset:IPlayable) : void 
		{
			asset.volume = 0;
		}
		
		/** @inheritDoc */
		public function unmute(id:String = null) : IAudioManager
		{
			return _forEach(id, _updateVolume);
		}
		
		/** @inheritDoc */
		public function has(id:String) : Boolean
		{
			return !!items[id];
		}
		
		/** @inheritDoc */
		public function retrieve(id:String) : IPlayable
		{
			return items[id];
		}
		
		/** @inheritDoc */
		public function remove(id:String = null) : IAudioManager
		{
			return _forEach(id, _dispose);
		}
		
		protected function _dispose(asset:IPlayable) : void 
		{
			asset.dispose();
			delete items[asset.id];
			delete gains[asset.id];
		}
		
		/** @inheritDoc */
		public function gain(id:String, gain:Number) : IAudioManager
		{
			return this._forEach(id, function(asset:IPlayable) : void {
				gains[ asset.id ] = gain;
				_updateVolume(asset);
			});
		}
		
		/* Properties */
		
		/** @inheritDoc */
		public function get masterVolume() : Number
		{
			return master;
		}
		
		/** @inheritDoc */
		public function set masterVolume(num:Number) : void
		{
			master = num;
			_forEach(null, _updateVolume);
		}
	}
}
